// Copyright (c) 2023 Presto Labs Pte. Ltd.
// Author: junxiao, leon

#include <cmath>
#include <memory>
#include <string>
#include <utility>

#include "coin2/strategy/dex_strat/simple_arb_strategy.h"

namespace coin2::strategy::dex_strat {
namespace {

coin::proto::LatencyProto::LatencyTag GetFeedLatencyTag(const FeedUpdate& upd) {
  if (upd.is_book())
    return coin::proto::LatencyProto::BOOK_FEED_LATENCY;
  else if (upd.is_trade())
    return coin::proto::LatencyProto::TRADE_FEED_LATENCY;
  else
    return coin::proto::LatencyProto::FEED_LATENCY;
}

coin::proto::AccountRequestProto GetAccRequest(const MarketExchangeApi& mea) {
  coin::proto::AccountRequestProto acc_request;
  acc_request.set_market_type(MarketType_Name(mea.market));
  acc_request.set_exchange(ExchangeType_Name(mea.exchange));
  acc_request.set_api_version(mea.api);
  return acc_request;
}

std::string GetProductKey(const IProduct* product) {
  return fmt::format("{}.{}", product->absolute_norm(), product->exchange_name());
}

std::string GetProductKey(const OrderEvent* oe) {
  return fmt::format("{}.{}", oe->symbol(), ExchangeTypeToString(oe->exchange_type()));
}

bool HasMidPrice(const FeedUpdate& upd) {
  bool has_midp = false;
  if (upd.book().Bid0().has_value() &&
      upd.book().Ask0().has_value() &&
      upd.book().Bid0().value().price < upd.book().Ask0().value().price) {
    has_midp = true;
  }
  return has_midp;
}

std::optional<double> GetMidPrice(const FeedUpdate& upd) {
  if (HasMidPrice(upd)) {
    return (upd.book().Bid0().value().price + upd.book().Ask0().value().price) / 2;
  } else {
    return std::nullopt;
  }
}

void ConvertExecutorConfig(AggressiveExecutorConfig* executor_config) {
  if (executor_config->has_order_update_period_sec()) {
    executor_config->set_order_update_period(
        executor_config->order_update_period_sec() * 1e9);
  }
  if (executor_config->has_min_posting_period_sec()) {
    executor_config->set_min_posting_period(
        executor_config->min_posting_period_sec() * 1e9);
  }
  if (executor_config->has_max_posting_period_sec()) {
    executor_config->set_max_posting_period(
        executor_config->max_posting_period_sec() * 1e9);
  }
  if (executor_config->has_fill_cooldown_period_sec()) {
    executor_config->set_fill_cooldown_period(
        executor_config->fill_cooldown_period_sec() * 1e9);
  }
}

void InitPassiveExecutorConfig(
    const AggressiveExecutorConfig& agg_config,
    PassiveExecutorConfig* pass_config) {
  pass_config->set_mea(agg_config.mea());
  pass_config->set_symbol(agg_config.symbol());
  pass_config->set_min_pos(agg_config.min_pos());
  pass_config->set_max_pos(agg_config.max_pos());
  pass_config->set_reserve((agg_config.min_pos() + agg_config.max_pos())/2);
  pass_config->set_lot_size(agg_config.lot_size());
  pass_config->set_leverage(agg_config.leverage());
  pass_config->set_max_posting_period(agg_config.max_posting_period());
  pass_config->set_max_working_cnt(agg_config.max_working_cnt());
  pass_config->set_order_update_period(agg_config.order_update_period());
  pass_config->set_fill_cooldown_period(agg_config.fill_cooldown_period());
}
}  // namespace

SimpleArbPricer::SimpleArbPricer(
    const IProduct* trade_product,
    const IProduct* main_ref_product,
    RefProductConvertDirection ref_convert_direction,
    const IProduct* convert_ref_product,
    int64_t max_queue_size,
    double arb_diff_bar,
    double arb_leave_bar,
    double arb_stop_price_diff,
    int64_t tick_ts_diff_allowed) 
    : max_queue_size_(max_queue_size), arb_diff_bar_(arb_diff_bar), arb_leave_bar_(arb_leave_bar),
      arb_stop_price_diff_(arb_stop_price_diff), tick_ts_diff_allowed_(tick_ts_diff_allowed) {
  trade_product_key_ = GetProductKey(trade_product);
  main_ref_key_ = GetProductKey(main_ref_product);
  if (ref_convert_direction != RefProductConvertDirection::NONE && convert_ref_product != nullptr) {
    ref_product_convert_direction_ = ref_convert_direction;
    convert_ref_key_ = GetProductKey(convert_ref_product);
  } else {
    ref_product_convert_direction_ = RefProductConvertDirection::NONE;
  }
  current_op_ = {false, {0, OrderSide::UNKNOWN_ORDER_SIDE}};
  current_pos_side_ = 0;
  order_price_ = 0.0;
}

bool SimpleArbPricer::Ready() {
  return signal_queue_.size() >= max_queue_size_;
}

void SimpleArbPricer::onBookFeed(const std::string& product_key, const FeedUpdate& upd) {
  //CHECK(product_key == product_key_) << product_key << " vs " << product_key_;
  if (product_key.length() == 0 || (product_key != trade_product_key_ && product_key != main_ref_key_ && product_key != convert_ref_key_)) {
    return;
  }
  if (!HasMidPrice(upd)) {
    LOG(INFO) << fmt::format(
        "Abnormal feed. product: {}", upd.product().absolute_norm());
    return;
  }

  if (product_key == main_ref_key_) {
    last_main_ref_ts_ = upd.book().Timestamp();
    last_main_ref_ask0_ = upd.book().Ask0();
    last_main_ref_bid0_ = upd.book().Bid0();
  } else if (product_key == convert_ref_key_) {
    last_convert_ref_ts_ = upd.book().Timestamp();
    last_convert_ref_ask0_ = upd.book().Ask0();
    last_convert_ref_bid0_ = upd.book().Bid0();
  } else if (product_key == trade_product_key_) {
    if (!last_main_ref_ts_ || !last_main_ref_ask0_ || !last_main_ref_bid0_) {
      return;
    }
    double ref_ask0 = last_main_ref_ask0_.value().price;
    double ref_bid0 = last_main_ref_bid0_.value().price;
    double trade_ask0 = upd.book().Ask0().value().price;
    double trade_bid0 = upd.book().Bid0().value().price;
    if (ref_product_convert_direction_ != RefProductConvertDirection::NONE) {
      if (!last_convert_ref_ts_ || !last_convert_ref_ask0_ || !last_convert_ref_bid0_) {
        return;
      }
      double convert_midp = (last_convert_ref_ask0_.value().price + last_convert_ref_bid0_.value().price) / 2.0;
      if (ref_product_convert_direction_ == RefProductConvertDirection::MULTIPLE) {
        ref_ask0 *= convert_midp;
        ref_bid0 *= convert_midp;
      } else if (ref_product_convert_direction_ == RefProductConvertDirection::DIVIDE) {
        ref_ask0 /= convert_midp;
        ref_bid0 /= convert_midp;
      }
    }
    LOG(INFO) << fmt::format(
        "ref product: {}, ask0: {}, bid0: {}",
        main_ref_key_, ref_ask0, ref_bid0);
    
    signal_queue_.push_back(SimpleArbTickEntry(
      upd.book().Timestamp(), trade_ask0, trade_bid0,
      last_main_ref_ts_.value(), ref_ask0, ref_bid0
    ));
    if (signal_queue_.size() > max_queue_size_) {
      signal_queue_.pop_front();
    }
    CalculateCurrentOperation();
  }
}

void SimpleArbPricer::onPosChanged(int pos_side, double order_price) {
  LOG(INFO) << fmt::format(
        "SimpleArbPricer::onPosChanged: pos_side: {}, order_price: {}",
        pos_side, order_price);
  bool is_pos_same = pos_side == current_pos_side_;
  current_pos_side_ = pos_side;
  order_price_ = order_price;
  if (!is_pos_same) {
    CalculateCurrentOperation();
  }
}

bool SimpleArbPricer::IsStartSellEntry(const SimpleArbTickEntry& tick_entry) {
  return tick_entry.ref_ask0 < tick_entry.trade_bid0 - arb_diff_bar_;
}

bool SimpleArbPricer::IsStartBuyEntry(const SimpleArbTickEntry& tick_entry) {
  return tick_entry.ref_bid0 > tick_entry.trade_ask0 + arb_diff_bar_;
}

bool SimpleArbPricer::IsReturnSellEntry(const SimpleArbTickEntry& tick_entry) {
  return tick_entry.ref_ask0 > tick_entry.trade_bid0 - arb_leave_bar_;
}

bool SimpleArbPricer::IsReturnBuyEntry(const SimpleArbTickEntry& tick_entry) {
  return tick_entry.ref_bid0 < tick_entry.trade_ask0 + arb_leave_bar_;
}

bool SimpleArbPricer::ShouldStartSell() {
  if (!Ready()) {
    return false;
  }
  for (auto& tick_entry : signal_queue_) {
    if (!IsStartSellEntry(tick_entry)) {
      return false;
    }
  }
  LOG(INFO) << "SimpleArbPricer: signal - StartSell";
  return true;
}

bool SimpleArbPricer::ShouldStartBuy() {
  if (!Ready()) {
    return false;
  }
  for (auto& tick_entry : signal_queue_) {
    if (!IsStartBuyEntry(tick_entry)) {
      return false;
    }
  }
  LOG(INFO) << "SimpleArbPricer: signal - StartBuy";
  return true;
}

bool SimpleArbPricer::ShouldReturnSell() {
  if (!Ready()) {
    return false;
  }
  bool result = true;
  for (auto& tick_entry : signal_queue_) {
    if (!IsReturnSellEntry(tick_entry)) {
      result = false;
      break;
    }
  }
  bool result2 = signal_queue_.back().trade_bid0 - order_price_ > arb_stop_price_diff_;
  if (result) {
    LOG(INFO) << "SimpleArbPricer: signal - ReturnSell - bias meets requirement";
  }
  if (result2) {
    LOG(INFO) << "SimpleArbPricer: signal - ReturnSell - price diff meets requirement";
  }
  return result || result2;
}

bool SimpleArbPricer::ShouldReturnBuy() {
  if (!Ready()) {
    return false;
  }
  bool result = true;
  for (auto& tick_entry : signal_queue_) {
    if (!IsReturnBuyEntry(tick_entry)) {
      result = false;
      break;
    }
  }
  bool result2 = order_price_ - signal_queue_.back().trade_ask0 > arb_stop_price_diff_;
  if (result) {
    LOG(INFO) << "SimpleArbPricer: signal - ReturnBuy - bias meets requirement";
  }
  if (result2) {
    LOG(INFO) << "SimpleArbPricer: signal2 - ReturnBuy - price diff meets requirement";
  }
  return result || result2;
}

void SimpleArbPricer::CalculateCurrentOperation() {
  if (!Ready()) {
    return;
  }

  auto last_tick_entry = signal_queue_.back();
  /* since binance data is l1_realtime, no need to check ts diff
  if (std::abs(last_tick_entry.trade_ts - last_tick_entry.ref_ts) > tick_ts_diff_allowed_) {
    current_op_ = {false, {0, OrderSide::UNKNOWN_ORDER_SIDE}};
    return;
  }
  */
  std::pair<bool, std::pair<double, OrderSide>> result_op = {false, {0, OrderSide::UNKNOWN_ORDER_SIDE}};
  if (current_pos_side_ > 0) {
    if (ShouldReturnBuy()) {
      result_op = {true, {last_tick_entry.trade_bid0, OrderSide::SELL_ORDER}};
    }
  } else if (current_pos_side_ < 0) {
    if (ShouldReturnSell()) {
      result_op = {true, {last_tick_entry.trade_ask0, OrderSide::BUY_ORDER}};
    }
  } else {
    if (ShouldStartBuy()) {
      result_op = {true, {last_tick_entry.trade_ask0, OrderSide::BUY_ORDER}};
    } else if (ShouldStartSell()) {
      result_op = {true, {last_tick_entry.trade_bid0, OrderSide::SELL_ORDER}};
    }
  }
  current_op_ = result_op;
}


std::pair<bool, std::pair<double, OrderSide>> SimpleArbPricer::CalculatePrice() {
  return current_op_;
}

SimpleArbStrategy::SimpleArbStrategy(
    const std::experimental::filesystem::path& strat_json,
    bool dry_run,
    std::optional<int64_t> timestamp)
  : strategy_created_time_(timestamp.has_value() ? *timestamp : GetCurrentTimestamp()) {
  std::ifstream in(strat_json);
  LOG(INFO) << "Load strategy json: " << strat_json;
  CHECK_THROW(in.is_open());
  auto strat_config_str = ::nlohmann::json::parse(in).dump();
  SimpleArbStrategyConfig strat_config;
  auto status = google::protobuf::util::JsonStringToMessage(
      strat_config_str, &strat_config);
  CHECK_THROW(status.ok()) << "Fail to parse DriverConfig from " << strat_config_str
                           << "\n" << status;
  for (auto& product_config : *strat_config.mutable_product_configs()) {
    product_config.mutable_agg_config()->set_symbol(product_config.trade_symbol());
    product_config.mutable_agg_config()->set_mea(product_config.trade_mea());
    ConvertExecutorConfig(product_config.mutable_agg_config());
  }
  LOG(INFO) << strat_config.DebugString();
  for (auto& product_config : strat_config.product_configs()) {
    simple_arb_sub_strats_.push_back(std::make_unique<SimpleArbSubStrategy>(
        this,
        product_config,
        strategy_created_time_,
        strat_config.enable_telemetry(),
        dry_run));
  }
  for (auto& sub_strat : simple_arb_sub_strats_) {
    auto key = GetProductKey(sub_strat->GetTradeProduct());
    feed_sub_map_[key].push_back(sub_strat.get());
    CHECK(order_sub_map_.find(key) == order_sub_map_.end());
    order_sub_map_[key] = sub_strat.get();

    key = GetProductKey(sub_strat->GetMainRefProduct());
    feed_sub_map_[key].push_back(sub_strat.get());

    if ((sub_strat->GetConvertRefProduct()) != nullptr) {
      key = GetProductKey(sub_strat->GetConvertRefProduct());
      feed_sub_map_[key].push_back(sub_strat.get());
    }
  }
}

void SimpleArbStrategy::InitAuthKey(::coin2::app::Driver* driver) {
  const auto& driver_config = driver->config();
  for (const auto& [exchange, order_config] : driver_config.order().exchanges()) {
    CHECK(!auth_key_);
    const auto& key_filepath = order_config.connection_config().key_filepath();
    auth_key_.reset(new AuthKey(AuthKey::FromFile(key_filepath)));
  }
}

void SimpleArbStrategy::Init(::coin2::app::Driver* driver) {
  LOG(INFO) << "Simple Arb Strategy Init.";
  InitAuthKey(driver);
  strat_reporter_.reset(new StrategyReporter2(
      driver->strategy()->config()));
  for (auto& sub_strat : simple_arb_sub_strats_) {
    sub_strat->Init(driver, strat_reporter_.get());
    auto acc_request = GetAccRequest(sub_strat->mea());
    acc_request.set_owner(auth_key_->owner());
    auto curr_time = GetCurrentTimestamp();
    PassiveExecutorConfig pass_config;
    InitPassiveExecutorConfig(sub_strat->GetConfig().agg_config(), &pass_config);
    strat_reporter_->RegisterExecutorConfig(
        curr_time, acc_request,
        *sub_strat->GetTradeProduct(), pass_config);
  }
}

void SimpleArbStrategy::InjectFeed(const coin2::feed::mgr::impl::FeedSubsystemManager* feed_mgr) {
  for (auto& elem : feed_sub_map_) {
    for (auto& sub_strat : elem.second) {
      sub_strat->InjectFeed(feed_mgr);
    }
  }
}

void SimpleArbStrategy::onBookFeed(const FeedUpdate& upd) {
  const auto& key = GetProductKey(&upd.product());
  CHECK_GT(feed_sub_map_[key].size(), 0);
  for (auto& sub_strat : feed_sub_map_[key]) {
    sub_strat->onBookFeed(key, upd);
  }
  if (order_sub_map_.find(key) != order_sub_map_.end()) {
    auto midp = GetMidPrice(upd);
    if (midp.has_value()) {
      strat_reporter_->UpdateMidp(*order_sub_map_[key]->GetTradeProductForReporter(), midp);
    }
  }
}

void SimpleArbStrategy::onAccountInfo(const OrderUpdate& upd) {
  for (auto& sub_strat : simple_arb_sub_strats_) {
    sub_strat->onAccountInfo(upd);
  }
  if (strat_reporter_) {
    strat_reporter_->onAccountInfo(upd);
  }
}

void SimpleArbStrategy::onAccountOrder(const OrderUpdate& upd) {
  if (upd.product_order_info().event().type() == OrderEvent::ORDER_FILLED) {
    const auto& key = GetProductKey(&upd.product_order_info().event());
    if (order_sub_map_.count(key) == 0) {
      LOG(INFO) << fmt::format("Received unexpected fills {}", key);
    } else {
      order_sub_map_[key]->onAccountOrder(upd);
    }
  }
}

void SimpleArbStrategy::onOrderLog(const coin::proto::OrderGatewayLog& order_log) {
  if (strat_reporter_) {
    strat_reporter_->GetMutableStrategyLogger()->WriteOrderLog(
        order_log,
        true,
        GetCurrentTimestamp());
  }
}

SimpleArbSubStrategy::SimpleArbSubStrategy(
    SimpleArbStrategy* parent,
    const SimpleArbProductConfig& product_config,
    int64_t strategy_created_time,
    bool enable_telemetry,
    bool dry_run)
  : parent_(parent),
    config_(product_config),
    strategy_created_time_(strategy_created_time),
    driver_(nullptr),
    strat_logger_(nullptr),
    enable_telemetry_(enable_telemetry),
    dry_run_(dry_run),
    trade_tick_cnt_(0), pos_initialized_(false), is_pos_updating_(false),
    is_last_order_return_type_(true), last_order_ts_(0), last_order_price_(0.0) {
  CHECK(parent_);
  CHECK(config_.has_trade_symbol());
  CHECK(config_.has_trade_mea());
  CHECK(config_.has_agg_config());
  CHECK(config_.has_parameter_config());
  CHECK(config_.has_main_ref_config());
  trade_product_ = CreateProductFromNormString(
      MarketExchangeApi::FromString(config_.trade_mea()),
      config_.trade_symbol(),
      strategy_created_time);
  feed_keys_.insert(GetProductKey(GetTradeProduct()));
  std::string trade_symbol_name = config_.trade_symbol();
  std::string processed_symbol_name = trade_symbol_name;
  int64_t dot_index = trade_symbol_name.rfind(".");
  if (dot_index != std::string::npos) {
    processed_symbol_name = trade_symbol_name.substr(0, dot_index);
  }
  trade_product_for_reporter_ = CreateProductFromNormString(
      MarketExchangeApi::FromString(config_.trade_mea()),
      processed_symbol_name,
      strategy_created_time);


  main_ref_product_ = CreateProductFromNormString(
      MarketExchangeApi::FromString(config_.main_ref_config().mea()),
      config_.main_ref_config().symbol(),
      strategy_created_time);
  ref_feed_keys_.insert(GetProductKey(main_ref_product_.get()));

  if (config_.ref_convert_direction() != RefProductConvertDirection::NONE && config_.has_convert_ref_config()) {
    ref_product_convert_direction_ = config_.ref_convert_direction();
    convert_ref_product_ = CreateProductFromNormString(
      MarketExchangeApi::FromString(config_.convert_ref_config().mea()),
      config_.convert_ref_config().symbol(),
      strategy_created_time);
    ref_feed_keys_.insert(GetProductKey(convert_ref_product_.get()));
  } else {
    ref_product_convert_direction_ = RefProductConvertDirection::NONE;
  }
  auto agg_config = config_.agg_config();
  auto parameter_config = config_.parameter_config();
  reserved_pos_ = agg_config.maintain_open_pos();
  lot_size_ = agg_config.lot_size();
  max_pos_ = agg_config.max_pos();
  min_pos_ = agg_config.min_pos();
  current_pos_ = reserved_pos_;
  
  arb_diff_bar_ = parameter_config.arb_diff_bar();
  arb_leave_bar_ = parameter_config.arb_leave_bar();
  arb_stop_price_diff_ = parameter_config.arb_stop_price_diff();
  signal_queue_size_ = parameter_config.signal_queue_size();
  pos_mismatch_bar_ = parameter_config.pos_mismatch_bar();
  order_tolerated_ratio_ = parameter_config.order_tolerated_ratio();
  order_cooldown_ = parameter_config.order_cooldown();
  safe_order_cooldown_ = parameter_config.safe_order_cooldown();
  tick_ts_diff_allowed_ = parameter_config.tick_ts_diff_allowed();

  pricer_ = std::make_unique<SimpleArbPricer>(
    trade_product_.get(), main_ref_product_.get(), ref_product_convert_direction_, convert_ref_product_.get(),
    signal_queue_size_, arb_diff_bar_, arb_leave_bar_, tick_ts_diff_allowed_
  );
}

void SimpleArbSubStrategy::Init(
    ::coin2::app::Driver* driver,
    ::coin2::strategy::util::StrategyReporter2* reporter) {
  driver_ = driver;
  strat_logger_ = reporter->GetMutableStrategyLogger();
  auto get_product_holder = [this](const coin2::exchange::base::symbology::IProduct& product, int64_t timestamp) {
      return driver_->product_holder_manager()->GetProductHolder(product, timestamp);
  };
  executor_ = std::make_unique<AggOrderExecutor>(
      config_.agg_config(), os(), get_product_holder);
  if (enable_telemetry_) {
    LOG(INFO) << "Set Latency Recorder";
    os()->gateway()->set_latency_recorder(
         strat_logger_->mutable_latency_recorder());
  }
}

void SimpleArbSubStrategy::InjectFeed(
    const coin2::feed::mgr::impl::FeedSubsystemManager* feed_mgr) {
  feed_mgr_ = feed_mgr;
}

void SimpleArbSubStrategy::onAccountInfo(const OrderUpdate& upd) {
  if (GetMutableExecutor() && pricer_->Ready()) {
  }
}

void SimpleArbSubStrategy::UpdatePosition() {
  if (!is_pos_updating_) {
    is_pos_updating_ = true;
    double real_cur_pos = executor_->GetPosition();
    if (std::abs(real_cur_pos - current_pos_) > 0.0001) {
      LOG(INFO) << fmt::format(
            "Fix pos from {} to {}.",
            current_pos_, real_cur_pos);
      int pos_side = 0;
      if (real_cur_pos  > reserved_pos_ + pos_mismatch_bar_) {
        pos_side = 1;
      } else if (real_cur_pos < reserved_pos_ - pos_mismatch_bar_) {
        pos_side = -1;
      }
      pricer_->onPosChanged(pos_side, last_order_price_);
      current_pos_ = real_cur_pos;
    }
    is_pos_updating_ = false;
  }
}

void SimpleArbSubStrategy::onBookFeed(const std::string& product_key, const FeedUpdate& upd) {
  CHECK(feed_keys_.find(product_key) != feed_keys_.end() or ref_feed_keys_.find(product_key) != ref_feed_keys_.end());
  if (HasMidPrice(upd)) {
    LOG(INFO) << fmt::format(
            "symbol:{}, ask0: {}, bid0: {}",
            product_key, upd.book().Ask0().value().price, upd.book().Bid0().value().price);
  }
  pricer_->onBookFeed(product_key, upd);

  if (!(os()->is_ready() && pricer_->Ready() && GetMutableExecutor())) {
    return;
  }

  if (feed_keys_.find(product_key) == feed_keys_.end()) {
    return;
  }

  trade_tick_cnt_++;
  if (!pos_initialized_) {
    last_order_price_ = (upd.book().Ask0().value().price + upd.book().Bid0().value().price) / 2.0;
    UpdatePosition();
    pos_initialized_ = true;
    return;
  }

  if (trade_tick_cnt_ % 5 == 0) {
    UpdatePosition();
  }

  if ((is_last_order_return_type_ && upd.book().Timestamp() - last_order_ts_ < safe_order_cooldown_)
    || (!is_last_order_return_type_ && upd.book().Timestamp() - last_order_ts_ < order_cooldown_)) {
      LOG(INFO) << "in order cooldown.";
      return;
  }

  auto ret = pricer_->CalculatePrice();
  if (ret.first) {
    auto [order_price, order_side] = ret.second;
    std::string order_side_str = order_side == OrderSide::BUY_ORDER ? "BUY" : (order_side == OrderSide::SELL_ORDER ? "SELL" : "UNKNOWN"); 
    LOG(INFO) << fmt::format(
            "Arb product: product: {}, price: {}, side: {}",
            trade_product_->absolute_norm(), order_price, order_side_str);
    double adjusted_order_price = order_price;
    if (order_side == OrderSide::BUY_ORDER) {
      adjusted_order_price *= 1.0 + order_tolerated_ratio_;
    } else if (order_side == OrderSide::SELL_ORDER) {
      adjusted_order_price *= 1.0 - order_tolerated_ratio_;
    }
    double adjusted_lot_size = config_.agg_config().lot_size();
    if (std::abs(current_pos_ - reserved_pos_) > pos_mismatch_bar_) {
      adjusted_lot_size = std::abs(current_pos_ - reserved_pos_);
    }
    LOG(INFO) << fmt::format(
            "adjusted_order_price: {}, adjusted_lot_size: {}",
            adjusted_order_price, adjusted_lot_size);
    bool order_result = executor_->SubmitAggOrders(order_side, adjusted_order_price, adjusted_lot_size);
    if (order_result) {
      LOG(INFO) << "Order submit succeeded.";
      if (std::abs(current_pos_ - reserved_pos_) < pos_mismatch_bar_) {
        is_last_order_return_type_ = false;
        last_order_ts_ = upd.book().Timestamp();
        last_order_price_ = order_price;
      } else {
        is_last_order_return_type_ = true;
        last_order_ts_ = upd.book().Timestamp();
      }
    } else {
      LOG(INFO) << "Order submit failed.";
      if (std::abs(current_pos_ - reserved_pos_) < pos_mismatch_bar_) {
        is_last_order_return_type_ = false;
        last_order_ts_ = upd.book().Timestamp();
      }
    }
  }

  
  if (os()->is_ready() && pricer_->Ready() && GetMutableExecutor()) {
    if (enable_telemetry_) {
      auto acc_request = GetAccRequest(upd.mea());
      auto feed_latency_tag = GetFeedLatencyTag(upd);
      coin2::strategy::util::SetFeedTimeToLatency(
          strat_logger_,
          feed_mgr_,
          upd,
          feed_latency_tag,
          acc_request,
          true);
      coin2::strategy::util::SetFeedTimeToLatency(
          strat_logger_,
          feed_mgr_,
          upd,
          coin::proto::LatencyProto::ORDER_LATENCY,
          acc_request,
          false);
    }
  }
}

}  // namespace coin2::strategy::dex_strat
